
package com.kweative.format;
import com.kweative.type.Node;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;

import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.stream.events.XMLEvent;
import org.codehaus.stax2.XMLInputFactory2;
import org.codehaus.stax2.XMLStreamReader2;
/**
 *
 * @author henrik
 */
public class XmlFormat extends Format {
	@Override
	public Node parse(InputStream xmlin) {
		/* Setup parser for mad speed... */
		XMLInputFactory2 xmlif = null ;
		xmlif = (XMLInputFactory2) XMLInputFactory2.newInstance();
		xmlif.setProperty(
				XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES,
				Boolean.FALSE);
		xmlif.setProperty(
				XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES,
				Boolean.FALSE);
		xmlif.setProperty(
				XMLInputFactory.IS_COALESCING,
				Boolean.FALSE);
		xmlif.configureForSpeed();
		LinkedList<Node> stack = new LinkedList<Node>();
		Node root = new Node("root");
		stack.add(root);
		String contents = "";
		try {
			XMLStreamReader2 xmlr = (XMLStreamReader2) xmlif.createXMLStreamReader(xmlin);
			while(xmlr.hasNext()){
				int eventType = xmlr.next();
				switch (eventType) {
					case XMLEvent.START_ELEMENT:
						Node child = new Node(xmlr.getName().toString());;
						for(int i = 0; i < xmlr.getAttributeCount();i++) {
							child.setAttribute(xmlr.getAttributeLocalName(i),xmlr.getAttributeValue(i));
						}
						stack.getFirst().addChild(child);
						stack.push(child);
						break;
					case XMLEvent.CHARACTERS:
						contents += xmlr.getText();
						break;
					case XMLEvent.END_ELEMENT:
						if (contents.length() > 0)
							stack.getFirst().setValue(contents);
						stack.pop();
						contents = "";
						break;
				}
			}
		} catch (XMLStreamException ex) {
			Logger.getLogger(XmlFormat.class.getName()).log(Level.SEVERE, null, ex);
		}
		return root.getFirst();
	}

	@Override
	public void serialize(Node node, OutputStream out) throws Exception {
        XMLOutputFactory factory = XMLOutputFactory.newInstance();
        XMLStreamWriter w = factory.createXMLStreamWriter(out);
        w.writeStartDocument("UTF-8","1.0");
        serializeNode(w, node);
        w.writeEndDocument();
	}
    private void serializeNode(XMLStreamWriter w,Node node) throws XMLStreamException {
        w.writeStartElement(node.getName());
        for(Iterator<String> it = node.attributes().keySet().iterator();it.hasNext();) {
            String key = it.next();
            String value = node.getAttribute(key).toString();
            w.writeAttribute(key, value);
        }
        if (node.hasChildren()) {
            if (node.getValue() != null && !node.getValue().toString().isEmpty()) {
                w.writeCData(node.getValue().toString());
            }
            for(Node child:node.children()) {
                serializeNode(w, child);
            }
        } else if (node.getValue() != null && !node.getValue().toString().isEmpty()) {
            w.writeCharacters(node.getValue().toString());
        }
        w.writeEndElement();
    }


}
